//
// Array.h
//
// Library: MongoDB
// Package: MongoDB
// Module:  Array
//
// Definition of the Array class.
//
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier:	BSL-1.0
//


#ifndef MongoDB_Array_INCLUDED
#define MongoDB_Array_INCLUDED


#include "Poco/MongoDB/Document.h"
#include "Poco/MongoDB/MongoDB.h"
#include "Poco/NumberFormatter.h"


namespace Poco
{
namespace MongoDB
{


    class MongoDB_API Array : public Document
    /// This class represents a BSON Array.
    {
    public:
        using Ptr = SharedPtr<Array>;

        Array();
        /// Creates an empty Array.

        virtual ~Array();
        /// Destroys the Array.

        // Document template functions available for backward compatibility
        using Document::add;
        using Document::get;

        template <typename T>
        Document & add(T value)
        /// Creates an element with the name from the current pos and value and
        /// adds it to the array document.
        ///
        /// The active document is returned to allow chaining of the add methods.
        {
            return Document::add<T>(Poco::NumberFormatter::format(size()), value);
        }

        Document & add(const char * value)
        /// Creates an element with a name from the current pos and value and
        /// adds it to the array document.
        ///
        /// The active document is returned to allow chaining of the add methods.
        {
            return Document::add(Poco::NumberFormatter::format(size()), value);
        }

        template <typename T>
        T get(std::size_t pos) const
        /// Returns the element at the given index and tries to convert
        /// it to the template type. If the element is not found, a
        /// Poco::NotFoundException will be thrown. If the element cannot be
        /// converted a BadCastException will be thrown.
        {
            return Document::get<T>(Poco::NumberFormatter::format(pos));
        }

        template <typename T>
        T get(std::size_t pos, const T & deflt) const
        /// Returns the element at the given index and tries to convert
        /// it to the template type. If the element is not found, or
        /// has the wrong type, the deflt argument will be returned.
        {
            return Document::get<T>(Poco::NumberFormatter::format(pos), deflt);
        }

        Element::Ptr get(std::size_t pos) const;
        /// Returns the element at the given index.
        /// An empty element will be returned if the element is not found.

        template <typename T>
        bool isType(std::size_t pos) const
        /// Returns true if the type of the element equals the TypeId of ElementTrait,
        /// otherwise false.
        {
            return Document::isType<T>(Poco::NumberFormatter::format(pos));
        }

        std::string toString(int indent = 0) const;
        /// Returns a string representation of the Array.

    private:
        friend void BSONReader::read<Array::Ptr>(Array::Ptr & to);
    };


    // BSON Embedded Array
    // spec: document
    template <>
    struct ElementTraits<Array::Ptr>
    {
        enum
        {
            TypeId = 0x04
        };

        static std::string toString(const Array::Ptr & value, int indent = 0)
        {
            //TODO:
            return value.isNull() ? "null" : value->toString(indent);
        }
    };


    template <>
    inline void BSONReader::read<Array::Ptr>(Array::Ptr & to)
    {
        to->read(_reader);
    }


    template <>
    inline void BSONWriter::write<Array::Ptr>(Array::Ptr & from)
    {
        from->write(_writer);
    }


}
} // namespace Poco::MongoDB


#endif // MongoDB_Array_INCLUDED
